package com.cmc.cloud.cmclink.doc.api.document;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cmc.cloud.cmclink.doc.api.document.emums.PartyTypeCodeEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.SiStatusEnum;
import com.cmc.cloud.cmclink.doc.api.document.rep.BlnoCheckSiRespDto;
import com.cmc.cloud.cmclink.doc.api.document.req.si.*;
import com.cmc.cloud.cmclink.doc.api.document.req.so.SoForecastBaseVO;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.BlnoCntrErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.BlnoErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.BlnoSpiltCombineDetailErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.SoErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.BlnoCntrMapper;
import com.cmc.cloud.cmclink.doc.mapper.BlnoMapper;
import com.cmc.cloud.cmclink.doc.mapper.BlnoPaymentMapper;
import com.cmc.cloud.cmclink.doc.mapper.BlnoScnMapper;
import com.cmc.cloud.cmclink.doc.service.si.BlnoService;
import com.cmc.cloud.cmclink.doc.service.si.BlnoSpiltCombineService;
import com.cmc.cloud.cmclink.doc.vo.blnocargovo.BlnoCargoUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.blnocntrvo.BlnoCntrUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.blnopaymentvo.BlnoPaymentUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.blnoscnvo.BlnoScnUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.blnospiltcombinevo.BlnoCombineChildVO;
import com.cmc.cloud.cmclink.doc.vo.blnospiltcombinevo.BlnoCombineVO;
import com.cmc.cloud.cmclink.doc.vo.blnospiltcombinevo.BlnoSpiltChildVO;
import com.cmc.cloud.cmclink.doc.vo.blnospiltcombinevo.BlnoSpiltVO;
import com.cmc.cloud.cmclink.doc.vo.blnovo.*;
import com.cmc.cloud.cmclink.doc.vo.blnovo.sisplitvo.AttachmentSplitChangeVO;
import com.cmc.cloud.cmclink.doc.vo.blnovo.sisplitvo.BlnoScnSplitChangeVO;
import com.cmc.cloud.cmclink.doc.vo.blnovo.sisplitvo.BlnoSplitCargoChangeVO;
import com.cmc.cloud.cmclink.doc.vo.blnovo.sisplitvo.RequirementsSplitChangeVO;
import com.cmc.cloud.cmclink.doc.vo.sovo.attachmentvo.AttachmentUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.sovo.requirementsvo.RequirementsUpdateReqVO;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.CommonResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import liquibase.pro.packaged.B;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.eventregistry.spring.EventRegistryFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * SI信息创建
 *
 * @author stq
 * @date 2025/7/7
 */
@Slf4j
@RestController
@Valid
public class SiSplitCombineApiImpl implements SiSplitCombineApi {

    private final static String CHARGE_CODE = "FRT";

    @Resource
    private BlnoSpiltCombineService blnoSpiltCombineService;
    @Resource
    private BlnoService blnoService;
    @Autowired
    private BlnoMapper blnoMapper;
    @Autowired
    private BlnoCntrMapper blnoCntrMapper;


    @Override
    public CommonResult<Void> checkOriginalSpiltData(Long originalBlnoId) {
        blnoSpiltCombineService.checkOriginalSpiltData(originalBlnoId);
        return CommonResult.success();
    }

    @Override
    public CommonResult<BlnoCheckSiRespDto> checkSi(BlnoCheckSiReqDto reqDto) {
        checkBlnoSplit(reqDto);
        BlnoCheckSiRespVO blnoCheckSiRespVO = new BlnoCheckSiRespVO();
        BlnoCheckSiReqVO reqVo = new BlnoCheckSiReqVO();
        BlnoInfoVO blnoInfoVo = BeanUtil.copyProperties(reqDto.getBlnoInfoDto(), BlnoInfoVO.class);
        reqVo.setBlnoInfoVO(blnoInfoVo);
        reqVo.setResponse(reqDto.getResponse());
        Boolean basicCheckFlag = blnoService.basicCheck(reqVo.getBlnoInfoVO(), blnoCheckSiRespVO, true);
        log.info("基本规则校验结果:{},校验明细阻断或警告:{}", basicCheckFlag, JSON.toJSONString(blnoCheckSiRespVO.getPrompts()));
        //提单箱和预配箱数量校验
        checkCntrSiInSo(blnoInfoVo.getBlnoBasInfoVO(),blnoInfoVo.getBlnoCntrs());
        blnoCheckSiRespVO.setCheckSuccessFlag(basicCheckFlag);
        BlnoCheckSiRespDto blnoCheckSiRespDto = BeanUtil.copyProperties(blnoCheckSiRespVO, BlnoCheckSiRespDto.class);
        return CommonResult.success(blnoCheckSiRespDto);
    }

    private void checkCntrSiInSo(BlnoBaseInfoVO blnoBasInfo, List<BlnoCntrUpdateReqVO> blnoCntrs) {
        List<SoForecastBaseVO> soForecast = blnoService.getSoForecastBySoId(blnoBasInfo.getId(), blnoBasInfo.getBlNo());
        if (CollectionUtil.isNotEmpty(soForecast) && CollectionUtil.isNotEmpty(blnoCntrs)) {
            Map<String, Long> cntrProperties = blnoCntrs.stream()
                    .collect(Collectors.groupingBy(
                            n -> n.getCntrType() + "-" + n.getCntrSize(),
                            Collectors.counting()
                    ));
            List<String> soCntrInfo = soForecast.stream().map(n -> n.getCntrType() + "-" + n.getCntrSize()).distinct().collect(Collectors.toList());
            Map<String, Long> soCntrMap = soForecast.stream().collect(Collectors.toMap(n -> n.getCntrType() + "-" + n.getCntrSize()
                    , SoForecastBaseVO::getCntrQuantity, (existing, replacement) -> existing));
            for (String key : cntrProperties.keySet()) {
                if (!soCntrInfo.contains(key)) {
                    throw ServiceExceptionUtil.exception(BlnoErrorCodeConstants.SI_SO_CNTR_NOT_EQUAL);
                }
                Long siNum = cntrProperties.get(key);
                Long soNum = soCntrMap.get(key);
                if (siNum.compareTo(soNum) > 0) {
                    throw ServiceExceptionUtil.exception(BlnoErrorCodeConstants.SI_LESS_THEN_SO);
                }
            }
        }
    }


    @Override
    public CommonResult<Long> blnoSpiltAndApply(BlnoSpiltReqDto blnoSpiltReqDto) {
        //开始拆单
        checkSplitCommit(blnoSpiltReqDto);
        BlnoSpiltVO blnoSpiltVO = new BlnoSpiltVO();
        blnoSpiltVO.setOriginalBlnoId(blnoSpiltReqDto.getOriginalBlnoId());
        blnoSpiltVO.setDataSource(blnoSpiltReqDto.getDataSource());
        List<BlnoSpiltChildDto> spiltChildDtos = blnoSpiltReqDto.getSpiltChildDtos();
        List<BlnoSpiltChildVO> spiltChildVos = BeanUtil.copyToList(spiltChildDtos, BlnoSpiltChildVO.class);
        blnoSpiltVO.setSpiltChildVos(spiltChildVos);

        Long operationId = blnoSpiltCombineService.commitBlnoSpiltNew(blnoSpiltVO);
        return CommonResult.success(operationId);
    }


    @Override
    public CommonResult<Long> blnoCombineAndApply(BlnoCombineDto blnoCombineDto) {
        //合并单前置校验
        /*Set<Long> blnoIds = blnoCombineDto.getSpiltChildDtos().stream().map(BlnoCombineChildDto::getBlnoId).collect(Collectors.toSet());
        blnoSpiltCombineService.checkOriginalCombineData(new ArrayList<>(blnoIds));*/
        BlnoCombineVO blnoCombine = new BlnoCombineVO();
        BlnoBeCombineDto blnoBeCombineDto = blnoCombineDto.getBlnoBeCombineDto();
        blnoCombine.setBlnoBeCombineVO(BeanUtil.copyProperties(blnoBeCombineDto, BlnoBeCombineVO.class));

        List<BlnoCombineChildDto> spiltChildDtos = blnoCombineDto.getSpiltChildDtos();
        blnoCombine.setSpiltChildVos(BeanUtil.copyToList(spiltChildDtos, BlnoCombineChildVO.class));

        List<BlnoCntrUpdateReqDto> cntrCombineChild = blnoCombineDto.getCntrCombineChild();
        blnoCombine.setCntrCombineChild(BeanUtil.copyToList(cntrCombineChild, BlnoCntrUpdateReqVO.class));
        blnoCombine.setBlnoCargoCombine(BeanUtil.copyProperties(blnoCombineDto.getBlnoCargoCombine(), BlnoCargoUpdateReqVO.class));
        blnoCombine.setAttachmentCombines(BeanUtil.copyToList(blnoCombineDto.getAttachmentCombines(), AttachmentUpdateReqVO.class));
        blnoCombine.setCombineDataSource(blnoCombineDto.getCombineDataSource());

        Long operationId = blnoSpiltCombineService.commitBlnoCombineNew(blnoCombine);
        return CommonResult.success(operationId);
    }

    @Override
    public CommonResult<BlnoSplitInfoDto> getSplitBlnoDetail(Long blnoId) {
        BlnoSplitInfoDto blnoSplitInfoDto = blnoSpiltCombineService.getSplitBlnoDetail(blnoId);
        return CommonResult.success(blnoSplitInfoDto);
    }

    @Override
    public CommonResult<List<BlnoCombineListDto>> listBlnoCombine(Long originalBlnoId) throws Exception {
        List<BlnoCombineListDto> blnoCombineListDtos = blnoSpiltCombineService.listBlnoCombine(originalBlnoId);
        return CommonResult.success(blnoCombineListDtos);
    }

    /**
     * 拆分单数据校验
     *
     * @param reqDto
     */
    private void checkBlnoSplit(BlnoCheckSiReqDto reqDto) {
        //查询主单信息
        BlnoBaseInfoDto blnoBasInfo = reqDto.getBlnoInfoDto().getBlnoBasInfoVO();
        String bookingNo = blnoBasInfo.getBookingNo();
        BlnoDO blno = blnoMapper.selectOne(new LambdaQueryWrapperX<BlnoDO>()
                .eqIfPresent(BlnoDO::getBookingNo, bookingNo)
                .eqIfPresent(BlnoDO::getPodBlFlag, true)
                .neIfPresent(BlnoDO::getSiStatus, SiStatusEnum.BookingDraft.getValue()).last("LIMIT 1"));
        if (Objects.isNull(blno)) {
            throw ServiceExceptionUtil.exception(BlnoErrorCodeConstants.BLNO_NOT_EXISTS);
        }
        List<BlnoCntrDO> blnoCntrs = blnoCntrMapper.selectList(new LambdaQueryWrapperX<BlnoCntrDO>().eqIfPresent(BlnoCntrDO::getBlnoId, blno.getId()));
        Map<String, BlnoCntrDO> blnoCntrMap = blnoCntrs.stream().collect(Collectors.toMap(BlnoCntrDO::getCntrNo, p -> p, (o1, o2) -> o1));
        List<BlnoCntrUpdateReqDto> splitBlnoCntrs = reqDto.getBlnoInfoDto().getBlnoCntrs();
        if (CollectionUtils.isEmpty(splitBlnoCntrs)) {
            return;
        }
        Map<String, BlnoCntrUpdateReqDto> splitSiCntrMap = splitBlnoCntrs.stream().collect(Collectors.toMap(BlnoCntrUpdateReqDto::getCntrNo, p -> p, (o1, o2) -> o1));
        //拆分单的箱必须在主单箱中存在，选中箱尺寸箱型必须和主单保持一致
        splitSiCntrMap.forEach((k, v) -> {
            if (!blnoCntrMap.containsKey(k)) {
                throw ServiceExceptionUtil.exception(BlnoCntrErrorCodeConstants.BLNO_CNTR_NOT_EXISTS);
            }
            BlnoCntrDO blnoCntr = blnoCntrMap.get(k);
            if (!Objects.equals(blnoCntr.getCntrSize(), v.getCntrSize()) || !Objects.equals(blnoCntr.getCntrType(), v.getCntrType())) {
                throw ServiceExceptionUtil.exception(BlnoCntrErrorCodeConstants.BLNO_CNTR_SIZE_TYPE_ERROR, v.getCntrNo());
            }
        });

    }

    /**
     * 提单拆单子单一箱多分票校验
     *
     * @param blnoSpiltReqDto 拆单参数
     */
    private void checkSplitCommit(BlnoSpiltReqDto blnoSpiltReqDto) {
        //查询原单
        BlnoDO blno = blnoMapper.selectById(blnoSpiltReqDto.getOriginalBlnoId());
        if (Objects.isNull(blno)) {
            throw ServiceExceptionUtil.exception(BlnoErrorCodeConstants.BLNO_NOT_EXISTS);
        }
        BlnoInfoVO siDetail = blnoService.getSiDetail(blno.getId());
        //查询原单箱信息
        List<BlnoCntrUpdateReqVO> blnoCntrs = siDetail.getBlnoCntrs();
        //查询原单收发通信息
        List<BlnoScnUpdateReqVO> blnoScns = siDetail.getBlnoScns();
        //查询原单的货物信息
        List<BlnoCargoUpdateReqVO> blnoCargos = siDetail.getBlnoCargos();
        //查询原单的付款方式
        List<BlnoPaymentUpdateReqVO> blnoPayments = siDetail.getBlnoPayments();
        //附加要求
        List<RequirementsUpdateReqVO> reqVOList = siDetail.getReqVOList();
        //附件
        List<AttachmentUpdateReqVO> attachments = siDetail.getAttachmentReqVO();

        Map<String, BlnoCntrUpdateReqVO> blnoCntrMap = blnoCntrs.stream().collect(Collectors.toMap(BlnoCntrUpdateReqVO::getCntrNo, p -> p, (o1, o2) -> o1));

        if (CollectionUtils.isEmpty(blnoCntrs) || CollectionUtils.isEmpty(blnoScns) || CollectionUtils.isEmpty(blnoCargos)
                ||CollectionUtils.isEmpty(blnoPayments)) {
            return;
        }
        Set<String> cntrNos = blnoCntrs.stream().map(BlnoCntrUpdateReqVO::getCntrNo).collect(Collectors.toSet());
        List<BlnoSpiltChildDto> spiltChildDtos = blnoSpiltReqDto.getSpiltChildDtos();
        if (CollectionUtils.isEmpty(spiltChildDtos)) {
            return;
        }
        List<BlnoCntrUpdateReqDto> allSplitCntrList = spiltChildDtos.stream()
                .flatMap(spiltChildDto -> spiltChildDto.getCntrSpiltChild().stream())
                .collect(Collectors.toList());
        Map<String, Long> cnrtNumMap = allSplitCntrList.stream().collect(Collectors.groupingBy(BlnoCntrUpdateReqDto::getCntrNo, Collectors.counting()));
        Set<String> splitCntrNos = allSplitCntrList.stream().distinct().map(BlnoCntrUpdateReqDto::getCntrNo).collect(Collectors.toSet());
        if (!cntrNos.equals(splitCntrNos)) {
            throw ServiceExceptionUtil.exception(BlnoCntrErrorCodeConstants.BLNO_CNTR_EQUALS_ERROR);
        }
        // 一箱多票筛选
        List<String> lclCntrNos = cnrtNumMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        // 子单一箱多票校验 - 找出包含一箱多票的子单
        List<BlnoSpiltChildDto> lclblnoList = spiltChildDtos.stream()
                .filter(spiltChildDto ->
                        spiltChildDto.getCntrSpiltChild().stream()
                                .map(BlnoCntrUpdateReqDto::getCntrNo)
                                .anyMatch(lclCntrNos::contains)
                )
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(lclblnoList)) {
            return;
        }
        lclblnoList.forEach(lclblno -> {
            //基础信息对比
            if (!StringUtils.equals(lclblno.getSpaceOwner(), blno.getSpaceOwner())
                    || !StringUtils.equals(lclblno.getCntrStatus(), blno.getCntrStatus())
                    || !StringUtils.equals(lclblno.getSignOrder(), blno.getSignOrder())
                    || !StringUtils.equals(lclblno.getSignType(), blno.getSignType())
                    || lclblno.getIssueFeederBl() != blno.getIssueFeederBl()
            ) {
                throw ServiceExceptionUtil.exception(BlnoSpiltCombineDetailErrorCodeConstants.BLNO_SPILT_BASE_INFO_ERROR);
            }
            //货物校验
            List<BlnoSplitCargoChangeVO> blnoSplitCargoChanges = BeanUtil.copyToList(blnoCargos, BlnoSplitCargoChangeVO.class);
            boolean cargoFlag = CollectionUtils.isEqualCollection(blnoSplitCargoChanges, BeanUtil.copyToList(Collections.singletonList(lclblno.getCargoChild()), BlnoSplitCargoChangeVO.class));
            if (!cargoFlag) {
                throw ServiceExceptionUtil.exception(BlnoSpiltCombineDetailErrorCodeConstants.BLNO_SPILT_CARGO_INFO_ERROR);
            }
            //付款方式
            BlnoPaymentUpdateReqDto blnoPaymentDto = lclblno.getPaymentSpiltChild().stream()
                    .filter(payment -> StringUtils.equals(payment.getChargeCode(), CHARGE_CODE))
                    .findAny().orElse(null);
            BlnoPaymentUpdateReqVO blnoPayment = siDetail.getBlnoPayments().stream()
                    .filter(payment -> StringUtils.equals(payment.getChargeCode(), CHARGE_CODE))
                    .findAny().orElse(null);
            boolean notSamePayment = Objects.nonNull(blnoPaymentDto) && Objects.nonNull(blnoPayment)
                    && (!StringUtils.equals(blnoPayment.getDesignatedPayment(), blnoPaymentDto.getDesignatedPayment())
                    || !StringUtils.equals(blnoPayment.getDefaultPayment(), blnoPaymentDto.getDefaultPayment()));
            if (notSamePayment) {
                throw ServiceExceptionUtil.exception(BlnoSpiltCombineDetailErrorCodeConstants.BLNO_SPILT_PAYMENT_INFO_ERROR);
            }
            //收货人和通知人必须一致
            List<BlnoScnSplitChangeVO> baseScns = BeanUtil.copyToList(blnoScns.stream()
                    .filter(p -> !p.getPartyTypeCode().equals(PartyTypeCodeEnum.SHIPPER.getValue())).collect(Collectors.toList()), BlnoScnSplitChangeVO.class);
            List<BlnoScnSplitChangeVO> lclBlnoScns = BeanUtil.copyToList(lclblno.getScnSpiltChild().stream()
                    .filter(p -> !p.getPartyTypeCode().equals(PartyTypeCodeEnum.SHIPPER.getValue())).collect(Collectors.toList()), BlnoScnSplitChangeVO.class);
            boolean scnFlag = CollectionUtils.isEqualCollection(baseScns, lclBlnoScns);
            if (!scnFlag){
                throw ServiceExceptionUtil.exception(BlnoSpiltCombineDetailErrorCodeConstants.BLNO_SPILT_SCN_INFO_ERROR);
            }
            //集装箱校验
            lclblno.getCntrSpiltChild().forEach(cntr->{
                if (!blnoCntrMap.containsKey(cntr.getCntrNo())){
                    throw ServiceExceptionUtil.exception(BlnoErrorCodeConstants.BLNO_NOT_EXISTS);
                }
                BlnoCntrUpdateReqVO baseCntr = blnoCntrMap.get(cntr.getCntrNo());
                if (!StringUtils.equals(baseCntr.getCntrNo(), cntr.getCntrNo())
                        || !StringUtils.equals(baseCntr.getCntrSize(), cntr.getCntrSize())
                        || !StringUtils.equals(baseCntr.getCntrType(), cntr.getCntrType())
                        || !StringUtils.equals(baseCntr.getSealNo(), cntr.getSealNo())
                        || !StringUtils.equals(baseCntr.getCntrOwner(), cntr.getCntrOwner())) {

                    throw ServiceExceptionUtil.exception(BlnoSpiltCombineDetailErrorCodeConstants.BLNO_SPILT_CNTR_INFO_ERROR);

                }
            });

        });


    }
}
